package org.oc.qaq.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.oc.qaq.context.UserContext;
import org.oc.qaq.entity.JwtUserDetails;
import org.oc.qaq.service.Impl.MyUserDetailService;
import org.oc.qaq.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Map;

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private MyUserDetailService userDetailsService;

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws IOException, ServletException {
        final String authorizationHeader = request.getHeader("Authorization");

        String username = null;
        String token = null;

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            token = authorizationHeader.substring(7);
            try {
                username = jwtUtil.extractClaims(token).getSubject();
            }
            catch (ExpiredJwtException e) {
                response.setContentType("application/json;charset=UTF-8");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getWriter().write(
                        new ObjectMapper().writeValueAsString(
                                Map.of(
                                        "code", 401,
                                        "message", "登录已过期，请重新登录"
                                )
                        )
                );
                return;
            }
            catch (Exception e) {
                response.setContentType("application/json;charset=UTF-8");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getWriter().write(
                        new ObjectMapper().writeValueAsString(
                                Map.of(
                                        "code", 401,
                                        "message", "无效的 Token"
                                )
                        )
                );
                return;
            }
        }

        try {
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

                    // ===== 新增：从 Redis 获取当前有效 token =====
                    String redisKey = "LOGIN_TOKEN:" + username;
                    String redisToken = (String) redisTemplate.opsForValue().get(redisKey);

                    // 如果 Redis 中不存在或不一致，则 token 已被登出或过期
                    if (!token.equals(redisToken)) {
                        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                        return;
                    }

                    UserDetails userDetails = userDetailsService.loadUserByUsername(username);

                    if (jwtUtil.validateToken(token, userDetails.getUsername())) {
                        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                                userDetails, null, userDetails.getAuthorities());
                        authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        SecurityContextHolder.getContext().setAuthentication(authToken);

                        if (authToken.getPrincipal() instanceof JwtUserDetails jwtUserDetails) {
                            UserContext.setCurrentId(jwtUserDetails.getUserId());
                        }
                    }
            }

            filterChain.doFilter(request, response);
        } finally {
            UserContext.removeCurrentId();
        }
    }
}
